//多进程版本
#pragma once

#include<iostream>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include"log.hpp"
#include<cstring>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

const uint16_t defaultport = 8080;
const std::string defaultip = "0.0.0.0";
const int number = 5;

log l;

class Server
{
public:
    Server(std::string ip=defaultip,uint16_t port=defaultport)
    :port_(port)
    ,ip_(ip)
    {}

    void Init()
    {
        socket_ = socket(AF_INET,SOCK_STREAM,0);
        if(socket_<0)
        {
            l(err,"socket创建失败：errno:%d,strerror%s:",errno,strerror(errno));
            exit(-1);
        }
        l(info,"套接字创建成功");
        
        //更改套接字属性
        int opt=1;
        if(setsockopt(socket_,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0)l(err,"套接字属性修改失败");
        l(info,"套接字属性修改成功");

        struct sockaddr_in s;
        s.sin_port=htons(port_);
        s.sin_addr.s_addr=inet_addr(ip_.c_str());
        s.sin_family=AF_INET;

        socklen_t len=sizeof(s);
        if(bind(socket_,reinterpret_cast<struct sockaddr*> (&s),len)<0) l(err,"bind套接字失败，errno:%d,strerror:%s",errno,strerror(errno));
        l(info,"bind套接字成功");

        //标记套接字为被动套接字
        if(listen(socket_,number)<0)    l(err,"listen更改失败，errno:%d,strerror:%s",errno,strerror(errno));
        l(info,"套接字被更改为被动套接字");
    }

    void Run()
    {
        char buff[size];
        struct sockaddr_in client;
        socklen_t len=sizeof(client);
        l(info,"进入循环开始通信");
        while(true)
        {
            int connfd = accept(socket_,reinterpret_cast<struct sockaddr*> (&client),&len);
            if(connfd<0)   l(err,"accept通信失败，errno:%d,strerror:%s",errno,strerror(errno));
            l(info,"建立连接成功"); 

            //开始接收并发送数据
            //单进程版本
            // ssize_t r;
            // while( (r=read(connfd,buff,sizeof(buff)-1)) >=0)
            // {
               
            //     if(r<0) l(err,"read失败errno:%d,strerror:%s",errno,strerror(errno));
            //     else if(r==0)   
            //     {
            //         int n=3;
            //         while( (r=read(connfd,buff,sizeof(buff)-1)) >=0&&n--)
            //         {
            //             l(comm,"消息读取失败，正在准备重新读取...");
            //             sleep(1);
            //         }
            //         if(r==0||n==0)  
            //         {
            //             l(err,"消息读取失败，正在准备退出...");
            //             std::cout<<"程序退出..."<<std::endl;
            //             exit(-1);
            //         }
            //     }
            //     buff[r]='\0';
            //     l(info,"read:消息获取成功");
            //     cout<<"client# "<<buff<<endl;
            // }
            
            pid_t son=fork();
            if(son==0)    //任务交给子进程进行管理
            {
                pid_t grandson=fork();
                if(grandson>0)  
                {
                    //子进程关闭
                    close(socket_);
                    exit(0);    //子进程退出,把孙进程交给操作系统管理
                }
                else
                {
                    Way(connfd,buff);
                }
                close(connfd);
                
            }

            close(connfd);
        }
        
    }

    void Way(int connfd,char* buff)
    {
        ssize_t r;
        while( (r=read(connfd,buff,sizeof(buff)-1)) >=0)
        {
            
            if(r<0) l(err,"read失败errno:%d,strerror:%s",errno,strerror(errno));
            else if(r==0)   
            {
                int n=3;
                while( (r=read(connfd,buff,sizeof(buff)-1)) >=0&&n--)
                {
                    l(comm,"消息读取失败，正在准备重新读取...");
                    sleep(1);
                }
                if(r==0||n==0)  
                {
                    l(err,"消息读取失败，正在准备退出...");
                    std::cout<<"程序退出..."<<std::endl;
                    exit(-1);
                }
            }
            buff[r]='\0';
            l(info,"read:消息获取成功");
            cout<<"client# "<<buff<<endl;
        }
    }

private:
    uint16_t port_;
    std::string ip_;
    int socket_;
};